package com.jingge.home.framework;

import com.jingge.home.util.LocalCacheManager;
import com.jingge.home.util.SpringUtil;
import com.jingge.home.util.wx.WxMessageBuilder;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.session.WxSessionManager;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.message.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.message.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.message.WxCpMessageHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 处理命令消息，由于快速验证，该消息处理器使用了大量不美观的if-else，后续命令增加会考虑使用命令模式重新设计
 *
 * @author Yongxiang
 * @date 2025-07-30 11:28
 * @email 1158055613@qq.com
 */
@Slf4j
@SuppressWarnings("unchecked")
@Component
public class CommandMsgHandler implements WxCpMessageHandler {
	/**
	 * 管理员单次授权可使用时长：分
	 */
	private static final int ADMIN_AUTH_TIME = 10;
	private static final Pattern PWD_PATTERN = Pattern.compile("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%.*#?&])[A-Za-z\\d@$!%.*#?&]{8,20}$");
	@Value("${wechat.currentAiAPIKey}")
	private String currentApiKey;
	@Value("${wechat.currentAiAPIKey}")
	private String defaultApiKey;
	@Autowired
	private LocalCacheManager<String, String> msgCache;
	@Value("${wechat.conversationSecret}")
	private String conversationSecret;
	@Value("${wechat.conversationSecret}")
	private String defaultConversationSecret;
	@Value("${wechat.adminSecret}")
	private String adminSecret;
	@Value("${wechat.maximumOnlineUserCount:10}")
	private Integer maximumOnlineUserCount;
	@Value("${wechat.aiUrl}")
	private String AI_URL;
	@Value("${wechat.expireTimePerAuth:180}")
	private Integer expireTimePerAuth;


	@Override
	@SuppressWarnings("unchecked")
	public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage,
	                                Map<String, Object> context,
	                                WxCpService wxCpService,
	                                WxSessionManager sessionManager) throws WxErrorException {
		LocalCacheManager<String, String> msgCache = SpringUtil.getNonnullBean(LocalCacheManager.class);
		String content = wxMessage.getContent();
		String to = wxMessage.getFromUserName();
		String from = wxMessage.getToUserName();
		String receiveMsgId = String.valueOf(wxMessage.getMsgId());
		//更多消息
		if (content.startsWith(CacheKeyConstant.MORE_MSG_PREFIX)) {
			String msgId = content.substring(CacheKeyConstant.MORE_MSG_PREFIX.length()).trim();
			String allMsg = msgCache.getAsString(msgId);
			if (StringUtils.isNotEmpty(allMsg)) {
				return WxMessageBuilder.buildTextMessage(allMsg, from, to);
			} else {
				return WxMessageBuilder.buildTextMessage("没有更多的消息啦", from, to);
			}
		}
		try {
			if (content.startsWith(CacheKeyConstant.COMMAND_PREFIX)) {
				if (msgCache.exist(CacheKeyConstant.LOCK_KEY)) {
					return WxMessageBuilder.buildTextMessage("抱歉！管理员已经锁定对话服务，详细情况请咨询公众号管理员", from, to);
				}
				String command = content.substring(CacheKeyConstant.COMMAND_PREFIX.length()).trim();
				if (StringUtils.isEmpty(command)) {
					log.info("指令为空");
					return WxMessageBuilder.buildTextMessage("指令为空", from, to);
				}
				if (!command.startsWith("a:") && !CacheKeyConstant.withAuth(to)) {
					return WxMessageBuilder.buildTextMessage("您好，您还没有得到授权与我对话，你可以通过指令\n“c:a:授权码”\n来进行授权", from, to);
				} else if (command.startsWith("a:")) {
					//进行授权
					String authCode = command.substring("a:".length());
					boolean isMatchTemporaryPwd = isMatchTemporaryPwd(authCode);
					if (conversationSecret.equals(authCode) || isMatchTemporaryPwd) {
						int expire = isMatchTemporaryPwd ? Integer.valueOf(msgCache.get(CacheKeyConstant.TEMPORARY_EXPIRE_PER_AUTH_PREFIX)) : expireTimePerAuth;
						if (getOnlineUserList().size() >= maximumOnlineUserCount) {
							return WxMessageBuilder.buildTextMessage("抱歉，现在系统用户人数已达到最大，请稍后再试", from, to);
						}
						authSuccess(to, expire);
						return WxMessageBuilder.buildTextMessage("恭喜，你已经获得{}分钟的对话授权，你可以通过指令“c:r”来查询剩余的对话时间，你可以通过指令“c:h”来查看你可供使用的指令列表。", from, to, expire);
					} else {
						return WxMessageBuilder.buildTextMessage("授权失败，授权码错误", from, to);
					}
				}
				if (command.startsWith("m:")) {
					log.info("获取更多消息");
					String msgId = command.substring("m:".length());
					String allMsg = msgCache.getAsString(msgId);
					if (StringUtils.isNotEmpty(allMsg)) {
						return WxMessageBuilder.buildTextMessage(allMsg, from, to);
					} else {
						return WxMessageBuilder.buildTextMessage("没有更多的消息啦", from, to);
					}
				} else if (command.startsWith("cl")) {
					log.info("清除会话历史");
					msgCache.remove(CacheKeyConstant.CONVERSATION_ID_PREFIX + to);
					return WxMessageBuilder.buildTextMessage("对话历史已清除", from, to);
				} else if (command.startsWith("r")) {
					log.info("查询剩余对话时长");
					return WxMessageBuilder.buildTextMessage("你的剩余对话时长为{}分钟", from, to, remainTime(to));
				} else if (command.startsWith("h")) {
					StringBuilder d = new StringBuilder();
					d.append(CacheKeyConstant.COMMAND_PREFIX).append("a:授权码-").append("获取对话授权").append("\n");
					d.append(CacheKeyConstant.COMMAND_PREFIX).append("m-").append("获取更多消息").append("\n");
					d.append(CacheKeyConstant.COMMAND_PREFIX).append("cl-").append("清除历史对话记忆").append("\n");
					d.append(CacheKeyConstant.COMMAND_PREFIX).append("r-").append("查看剩余对话时长");
					return WxMessageBuilder.buildTextMessage("支持的指令如下：\n{}", from, to, d);
				} else {
					log.info("未知指令");
					return WxMessageBuilder.buildTextMessage("未知指令，你可以使用如下指令查看支持的指令：\nc:h", from, to);
				}
			}

			//管理员指令
			if (content.startsWith(CacheKeyConstant.ADMIN_COMMAND_PREFIX)) {
				String command = content.substring(CacheKeyConstant.ADMIN_COMMAND_PREFIX.length()).trim();
				if (StringUtils.isEmpty(command)) {
					log.info("指令为空");
					return WxMessageBuilder.buildTextMessage("指令为空", from, to);
				}
				//授权
				if (!command.startsWith("a:") && !withAdminAuth(to)) {
					return WxMessageBuilder.buildTextMessage("您好，您还没有得到管理员的授权，无法执行管理员指令，你可以通过指令\n“a:a:授权码”\n来进行授权", from, to);
				} else if (command.startsWith("a:")) {
					//进行授权
					String authCode = command.substring("a:".length());
					if (adminSecret.equals(authCode)) {
						adminAuthSuccess(to);
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，你已经获得{}分钟的管理员授权，你可以通过指令“a:rm”来查询剩余时间。", from, to, ADMIN_AUTH_TIME);
					} else {
						return WxMessageBuilder.buildTextMessage("授权失败，授权码错误", from, to);
					}
				}

				if (command.startsWith("rm")) {
					log.info("查询剩余管理时长");
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，你的剩余管理时长为{}分钟", from, to, remainAdminTime(to));
				} else if (command.startsWith("h")) {
					StringBuilder d = new StringBuilder();
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("a:授权码-").append("获取管理授权")
							.append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("ca:新的AI API KEY-")
							.append("改变当前对接的AI服务").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("rpa-").append("重置到初始的AI服务")
							.append("\n");

					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("l:锁定时长（分钟）-").append("锁定对话服务")
							.append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("ul-").append("解锁对话服务").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("rl-").append("查询剩余锁定时长（分钟）")
							.append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("cp:新的密码-")
							.append("重置对话密码，并且强制下线所有用户").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("rpp-").append("重置到初始的对话密码")
							.append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("tp:临时密码:单次授权过期时长-")
							.append("启用临时对话密码").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("rtp-").append("移除临时密码").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("tprm-").append("查询临时密码剩余有效时长")
							.append("\n");

					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("etp:刷新时长（分钟）-")
							.append("刷新临时密码过期时长").append("\n");
					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("lu-").append("列举在线用户").append("\n");

					d.append(CacheKeyConstant.ADMIN_COMMAND_PREFIX).append("rm-").append("查看剩余管理时长");
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，支持的管理指令如下：\n{}", from, to, d);
				} else if (command.startsWith("ca:")) {
					String apiKey = command.substring("ca:".length());
					log.info("改变AI API Key newApiKey={}", apiKey);
					if (StringUtils.isNotEmpty(apiKey)) {
						msgCache.set(CacheKeyConstant.CURRENT_API_KEY, apiKey, 365, TimeUnit.DAYS);
						msgCache.remove(CacheKeyConstant.CONVERSATION_ID_PREFIX + to);
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，AI API Key已改变，当前为{}", from, to, apiKey);
					}
				} else if (command.startsWith("rpa")) {
					log.info("重置AI API Key");
					msgCache.set(CacheKeyConstant.CURRENT_API_KEY, defaultApiKey, 365, TimeUnit.DAYS);
					msgCache.remove(CacheKeyConstant.CONVERSATION_ID_PREFIX + to);
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，AI API Key已重置", from, to);
				} else if (command.startsWith("l:")) {
					String time = command.substring("l:".length());
					log.info("锁定服务，锁定时长为{}分钟", time);
					if (StringUtils.isEmpty(time)) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，锁定时长指定错误：{}", from, to, time);
					}
					try {
						msgCache.set(CacheKeyConstant.LOCK_KEY, "1", Integer.parseInt(time.trim()), TimeUnit.MINUTES);
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，服务锁定成功，锁定时长：{}分钟", from, to, time);
					} catch (Exception e) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，锁定时长指定错误：{}", from, to, time);
					}
				} else if (command.startsWith("ul")) {
					log.info("解锁服务");
					msgCache.remove(CacheKeyConstant.LOCK_KEY);
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，服务解锁成功", from, to);
				} else if (command.startsWith("rl")) {
					log.info("查询剩余锁定时长");
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，服务剩余锁定时长为{}分钟", from, to, remainLockTime());
				} else if (command.startsWith("cp:")) {
					String newPwd = command.substring("cp:".length());
					if (StringUtils.isEmpty(newPwd)) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，新的密码不能为空", from, to);
					}
					if (PWD_PATTERN.matcher(newPwd).matches()) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，新的密码不匹配规则，需要为8位到20位且包含字母、数字和特殊编码的字符串", from, to);
					}
					log.info("临时改变对话密码：{}", newPwd);
					conversationSecret = newPwd;
					int count = logoutAllUser();
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，对话密码已修改，为：{}，已强制下线{}个用户", from, to, newPwd, count);
				} else if (command.startsWith("rpp:")) {
					log.info("重置对话密码");
					conversationSecret = defaultConversationSecret;
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，对话密码已重置", from, to);
				} else if (command.startsWith("tp:")) {
					String tPwd = command.substring("tp:".length());
					int separatorIndex = tPwd.indexOf(":");
					String pwd = null;
					String expire = null;
					if (separatorIndex == -1) {
						pwd = tPwd;
						expire = String.valueOf(expireTimePerAuth);
					} else {
						pwd = tPwd.substring(0, separatorIndex);
						if (separatorIndex < tPwd.length() - 1) {
							expire = tPwd.substring(separatorIndex + 1);
						} else {
							expire = String.valueOf(expireTimePerAuth);
						}
					}
					if (StringUtils.isEmpty(pwd)) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码不能为空", from, to);
					}
					if (!PWD_PATTERN.matcher(pwd).matches()) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码不匹配规则，需要为8位到20位且包含字母、数字和特殊编码的字符串", from, to);
					}
					log.info("临时对话密码：{}", pwd);
					msgCache.set(CacheKeyConstant.TEMPORARY_PWD, pwd);
					msgCache.set(CacheKeyConstant.TEMPORARY_EXPIRE_PER_AUTH_PREFIX, expire);
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码已设置，为：{}，单次登录有效时长为{}分钟", from, to, pwd, expire);

				} else if (command.startsWith("rtp")) {
					log.info("移除临时密码");
					msgCache.remove(CacheKeyConstant.TEMPORARY_PWD);
				} else if (command.startsWith("etp:")) {
					String time = command.substring("etp:".length());
					log.info("设置临时密码过期，过期时长为{}分钟", time);
					if (StringUtils.isEmpty(time)) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码过期时长指定错误：{}", from, to, time);
					}
					try {
						if (msgCache.refreshExpiringTime(CacheKeyConstant.TEMPORARY_PWD, Integer.parseInt(time), TimeUnit.MINUTES) && msgCache.refreshExpiringTime(CacheKeyConstant.TEMPORARY_EXPIRE_PER_AUTH_PREFIX, Integer.parseInt(time), TimeUnit.MINUTES)) {
							return WxMessageBuilder.buildTextMessage("尊敬的管理员，刷新临时密码过期时长成功，过期时长：{}分钟", from, to, time);
						} else {
							return WxMessageBuilder.buildTextMessage("尊敬的管理员，刷新临时密码过期时长失败，可能是临时密码已过期", from, to);
						}
					} catch (Exception e) {
						return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码过期时长指定错误：{}", from, to, time);
					}
				} else if (command.startsWith("tprm")) {
					log.info("查询临时密码有效时间");
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，临时密码有效剩余时长为{}分钟", from, to, remainTemporaryPwdTime());
				} else if (command.startsWith("lu")) {
					log.info("列举在线用户");
					List<String> users = getOnlineUserList();
					StringBuilder userNames = new StringBuilder();
					users.forEach(user -> {
						userNames.append(user).append("\n");
					});
					return WxMessageBuilder.buildTextMessage("尊敬的管理员，当前在线用户个数为：{}\n用户名如下：\n{}", from, to, users.size(), userNames);
				} else {
					log.info("未知指令");
					return WxMessageBuilder.buildTextMessage("未知指令，你可以使用如下指令查看支持的指令：\na:h", from, to);
				}
			}
		} catch (Exception e) {
			log.error("指令处理异常", e);
			return WxMessageBuilder.buildTextMessage("指令处理失败，请检查", from, to);
		}
		return null;
	}

	private boolean withAdminAuth(String from) {
		return msgCache.exist(CacheKeyConstant.ADMIN_PREFIX + from);
	}

	private void authSuccess(String from,
	                         int expire) {
		msgCache.set(CacheKeyConstant.AUTH_KEY_PREFIX + from, "true", expire, TimeUnit.MINUTES);
	}

	private void adminAuthSuccess(String from) {
		msgCache.set(CacheKeyConstant.ADMIN_PREFIX + from, "1", ADMIN_AUTH_TIME, TimeUnit.MINUTES);
	}

	private long remainAdminTime(String from) {
		return remainKeyTime(CacheKeyConstant.ADMIN_PREFIX + from);
	}

	private long remainTime(String from) {
		return remainKeyTime(CacheKeyConstant.AUTH_KEY_PREFIX + from);
	}

	private long remainLockTime() {
		return remainKeyTime(CacheKeyConstant.LOCK_KEY);
	}

	private long remainTemporaryPwdTime() {
		return remainKeyTime(CacheKeyConstant.TEMPORARY_PWD);
	}

	private long remainKeyTime(String key) {
		long time = msgCache.getExpiringTime(key);
		return time > 0 ? (time / 1000) / 60 : 0;
	}

	private int logoutAllUser() {
		int count = 0;
		for (Map.Entry<String, String> entry : msgCache.entrySet()) {
			if (entry.getKey().startsWith(CacheKeyConstant.AUTH_KEY_PREFIX)) {
				msgCache.remove(entry.getKey());
				log.info("用户{}已下线", entry.getKey());
				count++;
			}
		}
		return count;
	}

	private boolean isMatchTemporaryPwd(String inPwd) {
		String t = msgCache.get(CacheKeyConstant.TEMPORARY_PWD);
		if (StringUtils.isEmpty(t)) {
			return false;
		}
		return t.equals(inPwd);
	}

	public List<String> getOnlineUserList() {
		return msgCache.entrySet().stream().filter(entry -> entry.getKey().startsWith(CacheKeyConstant.AUTH_KEY_PREFIX))
				.map(entry -> entry.getKey().substring(CacheKeyConstant.AUTH_KEY_PREFIX.length()))
				.collect(Collectors.toList());
	}
}
